#ifndef __MY_DATA_MANAGE__
#define __MY_DATA_MANAGE__

#include "config.hpp"
#include <unordered_map>
#include <pthread.h>
namespace cloud
{

    // 用作初始化备份文件的属性信息
    typedef struct BackupInfo
    {                    // c式结构体用法,让结构体名称可以直接使用BackupInfo,在c++中其实可以不用这么干,这里就当复习C了。
        bool pack_flag_; // 是否压缩标志
        time_t mtime_;
        time_t atime_;
        size_t fsize_;
        std::string real_path_; // 文件实际存储路径
        std::string url_;       // 请求URL中的资源路径
        std::string pack_path_; // 压缩包文件存储路径

        bool NewBackupInfo(const std::string &realpath)
        {
            // 初始化备份文件的信息
            xqlog::GetLogger("asynclogger")->Info("NewBackupInfo start");
            FileUtil f(realpath);
            if (!f.Exists())
            {
                xqlog::GetLogger("asynclogger")->Info("file not exists");
                return false;
            }
            pack_flag_ = false;
            mtime_ = f.LastAccessTime();
            atime_ = f.LastModifyTime();
            fsize_ = f.FileSize();
            real_path_ = realpath;
            // URL实际就是用户下载文件请求的路径
            // 下载路径前缀+文件名
            cloud::Config *config = cloud::Config::GetInstance();
            url_ = config->GetDownloadPrefix() + f.FileName();
            // packpath是用户压缩文件的路径
            // 压缩文件夹+文件名+文件后缀
            pack_path_ = config->GetPackDir() + f.FileName() + config->GetPackSuffix();
#ifdef DEBUG_LOG
            xqlog::GetLogger("asynclogger")->Debug("download_url:%s", url_.c_str());
            xqlog::GetLogger("asynclogger")->Debug("packpath:%s", pack_path_.c_str());
            xqlog::GetLogger("asynclogger")->Debug("pack_flag_:%s", pack_flag_);
            xqlog::GetLogger("asynclogger")->Debug("mtime_:%s", ctime(&mtime_));
            xqlog::GetLogger("asynclogger")->Debug("atime_:%s", ctime(&atime_));
            xqlog::GetLogger("asynclogger")->Debug("fsize_:%d", fsize_);
            xqlog::GetLogger("asynclogger")->Debug("real_path_:%s", real_path_.c_str());
#endif
            xqlog::GetLogger("asynclogger")->Info("NewBackupInfo end");
            return true;
        }
    } BackupInfo; // namespace BackupInfo

    class DataManager
    {
    private:
        std::string backup_file_;
        pthread_rwlock_t rwlock_;
        std::unordered_map<std::string, BackupInfo> table_;

    public:
        DataManager()
        {
            xqlog::GetLogger("asynclogger")->Info("DataManager construct start");
            backup_file_ = cloud::Config::GetInstance()->GetBackupFile();
            pthread_rwlock_init(&rwlock_, NULL);
            InitLoad();
            xqlog::GetLogger("asynclogger")->Info("DataManager construct end");
        }
        ~DataManager()
        {
            pthread_rwlock_destroy(&rwlock_);
        }

        bool InitLoad() // 初始化程序运行时从文件读取数据
        {
            cloud::FileUtil f(backup_file_);
            if (!f.Exists())
                return true;

            std::string body;
            if (!f.GetContent(&body))
                return false;

            // 反序列化
            Json::Value root;
            cloud::JsonUtil::UnSerialize(body, &root);
            // 3，将反序列化得到的Json::Value中的数据添加到table中
            for (int i = 0; i < root.size(); i++)
            {
                BackupInfo info;
                info.pack_flag_ = root[i]["pack_flag_"].asBool();
                info.fsize_ = root[i]["fsize_"].asInt();
                info.atime_ = root[i]["atime_"].asInt();
                info.mtime_ = root[i]["mtime_"].asInt();
                info.pack_path_ = root[i]["pack_path_"].asString();
                info.real_path_ = root[i]["real_path_"].asString();
                info.url_ = root[i]["url_"].asString();
                Insert(info);
            }
            return true;
        }

        bool Storage()
        { // 每次有信息改变则需要持久化存储一次
// 把table_中的数据转成json格式存入文件
#ifdef DEBUG_LOG
            xqlog::GetLogger("asynclogger")->Debug("message storage start");
#endif
            std::vector<BackupInfo> arr;
            if (!GetAll(&arr))
            {
                xqlog::GetLogger("asynclogger")->Warn("GetAll fail,can't get BackupInfo");
                return false;
            }

            Json::Value root; // root中存着json::value对象
            for (auto e : arr)
            {
                Json::Value item;
                item["pack_flag_"] = e.pack_flag_;
                item["mtime_"] = (Json::Int64)e.mtime_;
                item["atime_"] = (Json::Int64)e.atime_;
                item["fsize_"] = (Json::Int64)e.fsize_;
                item["url_"] = e.url_;
                item["real_path_"] = e.real_path_;
                item["pack_path_"] = e.pack_path_;
                root.append(item); // 作为数组
            }

            // 序列化
            std::string body;
#ifdef DEBUG_LOG
            xqlog::GetLogger("asynclogger")->Debug("new message for BackupInfo:%s", body.c_str());
#endif
            JsonUtil::Serialize(root, &body);

            // 写入文件
            FileUtil f(backup_file_);
            if (f.SetContent(body) == false)
                xqlog::GetLogger("asynclogger")->Warn("SetContent for BackupInfo Error");

#ifdef DEBUG_LOG
            xqlog::GetLogger("asynclogger")->Debug("message storage end");
#endif
            return true;
        }

        bool Insert(const BackupInfo &info)
        {
#ifdef DEBUG_LOG
            xqlog::GetLogger("asynclogger")->Debug("data_message Insert start");
#endif
            pthread_rwlock_wrlock(&rwlock_); // 加写锁
            table_[info.url_] = info;
            pthread_rwlock_unlock(&rwlock_);
            if (Storage() == false)
            {
                xqlog::GetLogger("asynclogger")->Error("data_message Insert:Storage Error");
                return false;
            }
#ifdef DEBUG_LOG
            xqlog::GetLogger("asynclogger")->Debug("data_message Insert end");
#endif
            return true;
        }

        bool Update(const BackupInfo &info)
        {
#ifdef DEBUG_LOG
            xqlog::GetLogger("asynclogger")->Debug("data_message Update start");
#endif
            pthread_rwlock_wrlock(&rwlock_);
            table_[info.url_] = info;
            pthread_rwlock_unlock(&rwlock_);
            if (Storage() == false)
            {
                xqlog::GetLogger("asynclogger")->Error("data_message Update:Storage Error");
                return false;
            }
#ifdef DEBUG_LOG
            xqlog::GetLogger("asynclogger")->Debug("data_message Update end");
#endif
            return true;
        }
        bool GetOneByURL(const std::string &key, BackupInfo *info)
        {
            pthread_rwlock_wrlock(&rwlock_);
            // URL是key，所以直接find()找
            if (table_.find(key) == table_.end())
            {
                return false;
            }
            *info = table_[key]; // 获取url对应的文件备份信息
            pthread_rwlock_wrlock(&rwlock_);
            return true;
        }
        bool GetOneByRealPath(const std::string &realpath, BackupInfo *info)
        {
            pthread_rwlock_wrlock(&rwlock_);
            // 遍历 通过realpath字段找到对应备份信息
            for (auto e : table_)
            {
                if (e.second.real_path_ == realpath)
                {
                    *info = e.second;
                    pthread_rwlock_wrlock(&rwlock_);
                    return true;
                }
            }
            pthread_rwlock_unlock(&rwlock_);
            return false;
        }
        bool GetAll(std::vector<BackupInfo> *arry)
        {
            pthread_rwlock_wrlock(&rwlock_);
            for (auto e : table_)
                arry->emplace_back(e.second);
            pthread_rwlock_unlock(&rwlock_);
            return true;
        }
    }; // namespace DataManager
}
#endif
